"""
---------------------------------------------------------------------
- File: router.py
- Date: 2025/7/10
- Author: yangzhide
- Email: xxzjyzd@126.com
- Description: 官方教程示例
---------------------------------------------------------------------
"""

import uuid
from typing import Union

from fastapi import Query, Path, Header, UploadFile
from fastapi import APIRouter, HTTPException, status
from pydantic.v1 import validate_model

from app.common.app_response import UnifiedResponse
from app.core.config import app_settings

# pydantic 数据模型
from .schemas import *

router = APIRouter(prefix="/guide", tags=["官方教程示例"])


@router.get("/path_parameters/{colorName}", summary="路径参数")
async def _(color_name: ModelName = Path(title="路径参数")):
    """
    ## 路径参数变量
    - 注意顺序，`/users/{user_id}` 之前声明 `/users/me`, 避免被匹配覆盖
    """
    return UnifiedResponse(data={"color_name": color_name})


@router.get("/query_parameters/", summary="查询参数")
async def _(
    skip: int = 0,
    limit: int = 10,
    q: str | None = Query(
        max_length=10, pattern="^y$", title="查询参数q", description="查询参数表述"
    ),
):
    """
    ## 查询参数
    - 声明的参数不是路径参数时：路径操作函数会把实参是`简单类型`时自动解释成**查询参数**
    """
    fake_items = [{"item_id": 100 + n, "q": q} for n in range(100)]
    return UnifiedResponse(data=fake_items[skip : skip + limit])


@router.post("/body_parameters/", summary="请求体参数")
async def _(body_item: BodyItem):
    """
    ## 请求体参数
    - 声明的参数不是路径参数时：路径操作函数会把实参是`Pydantic`模型时自动解释成**请求体**
    """
    b0 = body_item.model_dump()
    b1 = body_item.model_dump(include=["name"])
    b2 = body_item.model_dump(exclude=["name"])
    return UnifiedResponse(data={"b0": b0, "b1": b1, "b2": b2, **b0})


# ---用户登录---
def fake_password_hasher(raw_password: str):
    return "supersecret" + raw_password


def fake_save_user(user_in: UserIn):
    hashed_password = fake_password_hasher(user_in.password)
    user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
    return user_in_db


@router.post(
    "/user",
    summary="用户登录",
    status_code=status.HTTP_200_OK,
    response_model=UnifiedResponse[UserOut],
)
async def _(user_in: UserIn, user_no: str = Header(title="用户编号")):
    print("用于请求头：", user_no)
    user = fake_save_user(user_in)
    return UnifiedResponse(data=user)


# ---文件读取---
import os
from pathlib import Path
from fastapi import File, UploadFile


# 1. 解决重命名
def generate_unique_filename(directory: Path, original_filename: str):
    """生成唯一文件名，避免重复"""
    # 提取文件名和扩展名
    name, ext = os.path.splitext(original_filename)
    # 文件目录不存在则创建
    directory.mkdir(parents=True, exist_ok=True)
    # 尝试使用原始文件名
    file_path = Path(directory) / original_filename

    # 如果文件已存在，添加UUID后缀
    if file_path.exists():
        unique_id = uuid.uuid4().hex[:8]  # 取8位UUID
        new_filename = f"{name}_{unique_id}{ext}"
        return Path(directory) / new_filename
    return file_path


@router.post(
    "/upload_file/",
    summary="上传文件",
    response_description="单个文件上传，返回文件名、存储路径及大小",
)
async def _(file: UploadFile = File()):
    """
    文件上传：
    - 可上传同文件名文件
    """
    try:
        # 生成唯一文件名
        file_path = generate_unique_filename(
            Path(app_settings.APP_UPLOADS), file.filename
        )
        print("文件路径：", file_path)
        # 保存到磁盘
        with file_path.open("wb") as f:
            f.write(await file.read())
        return UnifiedResponse(
            data={
                "filename": file.filename,
                "path": file_path,
                "size": file_path.stat().st_size,
            }
        )

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    finally:
        await file.close()


# --- 依赖项---
from fastapi import Depends


async def common_paramenters(q: str | None = None, skip: int = 0, limit: int = 100):
    return {"q": q, "skip": skip, "limit": limit}


class CommonQueryParams:
    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
        self.q = q
        self.skip = skip
        self.limit = limit


@router.get("/ylx01", summary="函数依赖项01")
async def _(commons: dict = Depends(common_paramenters)):
    return commons


@router.get("/ylx02", summary="类依赖项01")
async def _(commons: CommonQueryParams = Depends()):
    return commons


# ---OAuth2安全性---
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from app.core.security import verify_password, get_password_hash, create_access_token

fake_users_db = {
    "yang": {
        "username": "yang",
        "full_name": "John Doe",
        "email": "johndoe@example.com",
        "hashed_password": "fakehashed123",
        "disabled": False,
    },
    "wang": {
        "username": "wang",
        "full_name": "Alice Wonderson",
        "email": "alice@example.com",
        "hashed_password": "fakehashed123",
        "disabled": True,
    },
}


def fake_hash_password(password: str):
    return "fakehashed" + password


oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/guide/token")


class Token(BaseModel):
    """返回的token"""

    access_token: str
    token_type: str


class TokenUser(BaseModel):
    username: str
    emai: str | None = None
    full_name: str | None = None
    disabled: bool | None = None


class TokenUserInDB(TokenUser):
    hashed_password: str


def get_user(db, username: str):
    if username in db:
        user_dict = db[username]
        return TokenUserInDB(**user_dict)
    else:
        return None


def authenticate_user(fake_db, username: str, password: str):
    user = get_user(fake_db, username)
    if not user:
        return False
    if not verify_password(password, user.hashed_password):
        return False
    return user


def fake_decode_token(token):
    user = get_user(fake_users_db, token)
    return user


async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = fake_decode_token(token)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的认证"
        )
    return user


async def get_current_active_user(current_user: TokenUser = Depends(get_current_user)):
    if current_user.disabled:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="无效的用户"
        )
    return current_user


@router.post("/token")
async def login(from_data: OAuth2PasswordRequestForm = Depends()):
    user_dict = fake_users_db.get(from_data.username)
    print("user_dict:::", user_dict)
    if not user_dict:
        raise HTTPException(status_code=400, detail="无限的用户名和密码")
    user = TokenUserInDB(**user_dict)
    print("加载到数据库模型后：", user.model_dump())
    hashed_password = fake_hash_password(from_data.password)
    print("hashed_password:::", hashed_password)
    print("user.hashed_password:::", user.hashed_password)
    if not hashed_password == user.hashed_password:
        raise HTTPException(status_code=400, detail="无效的用户名和密码")

    # 须返回字典格式， 不可用UnifiedResponse
    return {"access_token": user.username, "token_type": "bearer"}


@router.get("/users/me")
async def read_users_me(current_user: TokenUser = Depends(get_current_active_user)):
    return current_user
